package org.wattdepot.gdata.kukuicup.updater.energylastthirtydays;

import java.net.URL;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.gdata.kukuicup.service.GDataBatchRequest;
import org.wattdepot.gdata.kukuicup.service.GDataService;
import org.wattdepot.gdata.kukuicup.service.WattDepotService;
import org.wattdepot.gdata.kukuicup.updater.GDataCronTask;
import org.wattdepot.util.tstamp.Tstamp;
import it.sauronsoftware.cron4j.TaskExecutionContext;

/**
 * Gets the energy used by a source for the current day so far.
 * @author Philip Johnson
 */
public class EnergyLastThirtyDaysCurrentTask extends GDataCronTask {
  
  /**
   * Creates the task that gets woken up once a day to get the daily energy use for the last 7 days.
   * @param wattDepotService The WattDepot service configuration data. 
   * @param gdataService The gdata service configuration data.
   * @param spreadsheetURL The URL to the spreadsheet containing the data.
   * @param sourceName The WattDepot source of interest.
   * @param isVirtual True if the source is virtual.
   * @param row The row in the spreadsheet that this source's data appears in.
   */
  public EnergyLastThirtyDaysCurrentTask(WattDepotService wattDepotService, 
      GDataService gdataService, URL spreadsheetURL, String sourceName, boolean isVirtual, 
      int row) {
    super(wattDepotService, gdataService, spreadsheetURL, sourceName, row, 
        "EnergyLastThirtyDays", isVirtual);
  }

  /**
   * The method called once a day to update the data for the last seven days.
   * @param context Ignored.
   * @throws RuntimeException If problems occur (which they shouldn't). 
   */
  @Override
  public void execute(TaskExecutionContext context) throws RuntimeException {
    // Need to deal with missing data, like when sensors are not working. 
    System.out.format("%s Running EnergyLastThirtyDays/Current for source %s%n", 
        getTimestamp(), sourceName);

    // Get the current time. 
    XMLGregorianCalendar currTime = Tstamp.makeTimestamp();
    // Get the daily energy values for the past seven days.
    startWattDepotTiming();
    int energy = getTodaysEnergy();
    stopWattDepotTiming();

    if (energy >= 0) {
      startGDataTiming();
      // Add the actual data to the spreadsheet.
      GDataBatchRequest request = new GDataBatchRequest(gdataService, spreadsheetURL);
      try {
        // Add the last update field
        request.addRequest(this.row, 2, gdataService.makeLastUpdate(currTime));
        // Add the actual energy data. 
        request.addRequest(this.row, 3, String.valueOf(energy));
        // Send the request.
        request.sendRequest();
      }
      catch (Exception e) {
        System.out.println("Error making batch request for source " + this.sourceName);
        e.printStackTrace();
      }
      stopGDataTiming();
      printTaskResults("Last 30 days/current", "kWh", "OK");
    }
  }

  
  /**
   * Returns an integer with the amount of energy consumed so far today. 
   * @return An integer specifying today's energy consumption, or -1 if could not be determined.
   */
  private int getTodaysEnergy() {
    WattDepotClient client = this.wattDepotService.getClient();
    int energy = 0;
    // Get the end time.
    XMLGregorianCalendar endTime;
    XMLGregorianCalendar virtualEndTime;
    try {
      endTime = client.getLatestSensorData(sourceName).getTimestamp();
      // Kludge for virtual sources
      virtualEndTime = Tstamp.incrementMinutes(endTime, -1);
    }
    catch (Exception e1) {
      System.out.format("%s EnergyLastThirtyDays: Failed to get last sensor data for %s.%n", 
          getTimestamp(), sourceName);
      return -1;
    }
    // Get the start time (midnight of today).
    XMLGregorianCalendar startTime = Tstamp.makeTimestamp();
    startTime.setHour(0);
    startTime.setMinute(0);
    startTime.setSecond(0);
    startTime.setMillisecond(0);
    // Just after midnight, the last sensor data might be from the previous day, making 
    // startTime later than virtualEndTime.  So, check for that. 
    boolean startBeforeEnd = Tstamp.lessThan(startTime, virtualEndTime);
    try {
      energy = startBeforeEnd ? 
          (int) client.getEnergyConsumed(sourceName, startTime, virtualEndTime, 10) :
            0;
    }
    catch (Exception e) {
      System.out.format("%s EnergyLastThirtyDays: Failed to get energy for %s for day %s, %s%n", 
          getTimestamp(), sourceName, startTime, e.getMessage());
      return -1;
    }
    return energy;
  }

}
